package com.shisan.tingshu.account.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.shisan.tingshu.account.mapper.RechargeInfoMapper;
import com.shisan.tingshu.account.mapper.UserAccountMapper;
import com.shisan.tingshu.account.service.MqOpsService;
import com.shisan.tingshu.account.service.UserAccountService;
import com.shisan.tingshu.common.execption.ShisanException;
import com.shisan.tingshu.model.account.RechargeInfo;
import com.shisan.tingshu.model.account.UserAccount;
import com.shisan.tingshu.vo.account.AccountLockResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;

@Service
@Slf4j
public class MqOpsServiceImpl implements MqOpsService {

    @Autowired
    private UserAccountMapper userAccountMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private UserAccountService userAccountService;

    @Autowired
    private RechargeInfoMapper rechargeInfoMapper;

    /**
     * 用户账户初始化
     * @param content
     */
    @Override
    public void userAccountRegister(String content) {
        try {
            UserAccount userAccount = new UserAccount();
            userAccount.setUserId(Long.parseLong(content));
            int insert = userAccountMapper.insert(userAccount);
            log.info("用户账户初始化{}", insert > 0 ? "成功" : "失败");
        } catch (Exception e){
            throw new ShisanException(201, "服务内部处理数据失败");
        }
    }

    /**
     * 解锁“锁定金额返回对象”
     * @param orderNo
     */
    @Override
    public void listenUserAccountUnlock(String orderNo) {

        // 修改tingshu_account表的lock_amount(-)以及avaliable_amount(+)

        // 1、从Redis获取锁定的对象
        String dataKey = "user:account:amount:" + orderNo;
        String lockKey = "user:account:amount:lock:retry" + orderNo;
        String lockAmountResultStr = redisTemplate.opsForValue().get(dataKey); // CAS思想。防止正在解锁的时候，又来了一个解锁请求
        if (StringUtils.isEmpty(lockAmountResultStr)) { // 如果redis中已经没有锁定金额返回对象，说明已经解锁了
            return;
        }
        AccountLockResultVo accountLockResultVo = JSONObject.parseObject(lockAmountResultStr, AccountLockResultVo.class);
        Long userId = accountLockResultVo.getUserId();
        BigDecimal amount = accountLockResultVo.getAmount();
        String content = accountLockResultVo.getContent();
        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(lockKey, "1");
        if (aBoolean) {
            // 2.解锁
            try {
                int count = userAccountMapper.unLock(userId, amount);
                // 3.在流水表中记录解锁操作
                userAccountService.log(userId, amount, "解锁：" + content, orderNo, "1203-解锁");
                redisTemplate.delete(dataKey); // 正常干完活才能删除缓存标识key（不能放到finally中）
            } catch (Exception e) {
                throw new ShisanException(201, "解锁失败");
            } finally {
                // 4.删除缓存中的锁定对象
                redisTemplate.delete(lockKey);
            }
        }
    }

    /**
     * 消费
     * @param orderNo
     */
    @Override
    public void listenUserAccountMinus(String orderNo) {

        //  修改 lock_amount(-) 以及total_amount(-)
        // 1、从Redis获取锁定的对象
        String dataKey = "user:account:amount:" + orderNo;
        String lockKey = "user:account:minus:lock:" + orderNo;
        String lockAmountResultStr = redisTemplate.opsForValue().get(dataKey);
        if (StringUtils.isEmpty(lockAmountResultStr)) {
            return;
        }
        AccountLockResultVo accountLockResultVo = JSONObject.parseObject(lockAmountResultStr, AccountLockResultVo.class);
        Long userId = accountLockResultVo.getUserId();
        BigDecimal amount = accountLockResultVo.getAmount();
        String content = accountLockResultVo.getContent();
        // 2.解锁
        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(lockKey, "1");
        if (aBoolean) {
            try {
                int count = userAccountMapper.minus(userId, amount);
                // 3.在流水表中记录消费操作
                userAccountService.log(userId, amount, "消费：" + content, orderNo, "1204-消费");
                // 4.删除缓存中的锁定对象
                redisTemplate.delete(dataKey);
            } catch (Exception e) {
                throw new ShisanException(201, "消费失败");
            } finally {
                redisTemplate.delete(lockKey);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void userAccountOpsRecharge(String userId, String orderNo) {

        // 1.根据订单编号以及用户id查询零钱对象
        RechargeInfo rechargeInfo = rechargeInfoMapper.selectOne(
                new LambdaQueryWrapper<RechargeInfo>().eq(RechargeInfo::getOrderNo, orderNo).eq(RechargeInfo::getUserId, userId));
        if (rechargeInfo == null) {
            return;
        }
        // 2.修改零钱订单的状态
        int count = rechargeInfoMapper.updateRechargeStatus(userId, orderNo);
        log.info("修改零钱订单状态：{}", count > 0 ? "成功" : "失败");
        // 3.修改用户账户的余额信息
        int count1 = userAccountMapper.updateUserAccount(userId, rechargeInfo.getRechargeAmount());
        log.info("修用户账户信息：{}", count1 > 0 ? "成功" : "失败");
        // 4.记录用户账户流水
        userAccountService.log(Long.parseLong(userId), rechargeInfo.getRechargeAmount(), "充值:" + rechargeInfo.getRechargeAmount(), orderNo, "1201");
    }
}